#include <memory.h>
#include <stdio.h>
#include <stdlib.h>

#define QUO 0
#define RES 1

#define DIF 0
#define BOR 1

#define max(x, y) x ^ ((x ^ y) & -(x < y));

unsigned int N, N4;

unsigned char div5[50][2];

unsigned char div25[250][2];

unsigned short div239[2390][2];

unsigned char a[10240], b[10240], c[10240];

unsigned char difference[16][16][2];

void PRECALC_DIVIDE5() {
    unsigned char i;
    for( i = 0; i < 50; i++) {
        div5[i][QUO] = i / 5;
        div5[i][RES] = (i - div5[i][QUO] * 5) * 10;
    }
}

void PRECALC_DIVIDE25() {
    unsigned char i;
    for( i = 0; i < 250; i++) {
        div25[i][QUO] = i / 25;
        div25[i][RES] = (i - div25[i][QUO] * 25) * 10;
    }
}

void PRECALC_DIVIDE239() {
    unsigned short i;
    for( i = 0; i < 2390; i++) {
        div239[i][QUO] = i / 239;
        div239[i][RES] = (i - div239[i][QUO] * 239) * 10;
    }
}

void PRECALC_SUBTRACT()
{
    unsigned i, j;
    for (i = 0; i <= 10; i++)
    {
        for (j = 0; j <= 10; j++)
        {
            if (i < j)
            {
                difference[i][j][DIF] = i + 10 - j;
                difference[i][j][BOR] = 1;
            }
            else {
                difference[i][j][DIF] = i - j;
                difference[i][j][BOR] = 0;
            }
        }
    }
}

void DIVIDE5( char *x )
{
    unsigned k;
    unsigned char r, u;

    r = 0;
    for( k = 0; k <= N4; k++ )
    {
        u = r + x[k];
        x[k] = div5[u][QUO];
        r = div5[u][RES];
    }
}

void DIVIDE25( char *x )
{
    unsigned k;
    unsigned char r, u;

    r = 0;
    for( k = 0; k <= N4; k++ )
    {
        u = r + x[k];
        x[k] = div25[u][QUO];
        r = div25[u][RES];
    }
}

void DIVIDE239( char *x )
{
    unsigned k;
    unsigned short r, u;

    r = 0;
    for( k = 0; k <= N4; k++ )
    {
        u = r + x[k];
        x[k] = div239[u][QUO];
        r = div239[u][RES];
    }
}

void DIVIDE239x2( char *x )
{
    unsigned k;
    unsigned short a, r1, r2, u;

    r1 = r2 = 0;
    for( k = 0; k <= N4; k++ )
    {
        u = r1 + x[k];
        a = div239[u][QUO];
        r1 = div239[u][RES];
        u = r2 + a;
        x[k] = div239[u][QUO];
        r2 = div239[u][RES];
    }
}

# define d25d239x2(k) \
        u = rd + x[k]; \
        x[k] = div25[u][QUO]; \
        rd = div25[u][RES]; \
        u = r1 + y[k]; \
        dd = div239[u][QUO]; \
        r1 = div239[u][RES]; \
        u = r2 + dd; \
        y[k] = div239[u][QUO]; \
        r2 = div239[u][RES]; \


void DIVIDE25_DIVIDE239x2( char *x, char *y )
{
    unsigned k;
    unsigned char rd;
    unsigned short dd, r1, r2, u;

    rd = r1 = r2 = 0;
    for( k = 0; k <= N4 - 4; k += 4 )
    {
        d25d239x2(k+0);
        d25d239x2(k+1);
        d25d239x2(k+2);
        d25d239x2(k+3);
    }
}

#define longd(k) \
        cv = cache[rld][QUO]; \
        if (cv < 0) \
        { \
            z[k] = cache[rld][QUO] = rld * 10 / n; \
            rld = cache[rld][RES] = rld * 10 - rld * 10 / n * n; \
        } \
        else \
        { \
            z[k] = cv; \
            rld = cache[rld][RES]; \
        } \

void LONGDIV( char *z, int n )
{
    int cv, aux;
    unsigned rld, k, cache[20000][2];

    memset( cache, -1, 20000 * 2 * sizeof(int));
    z[0] = 0;
    rld = 1;

    for( k = 1; k <= N4 - 8; k += 8 )
    {
        longd(k+0);
        longd(k+1);
        longd(k+2);
        longd(k+3);
        longd(k+4);
        longd(k+5);
        longd(k+6);
        longd(k+7);
    }
}

# define d25d239x2_longd(k) d25d239x2(k) longd(k);

void DIVIDE25_DIVIDE239x2_LONGDIV( char *x, char *y, char *z, int n)
{
    int cv;
    unsigned rld, k, cache[20000][2];
    unsigned char rd;
    unsigned short dd, r1, r2, u;

    memset( cache, -1, 20000 * 2 * sizeof(int));
    z[0] = 0;
    rld = 1;
    rd = r1 = r2 = 0;
    d25d239x2(0);
    for( k = 1; k <= N4 - 8; k += 8 )
    {
        d25d239x2_longd(k+0);
        d25d239x2_longd(k+1);
        d25d239x2_longd(k+2);
        d25d239x2_longd(k+3);
        d25d239x2_longd(k+4);
        d25d239x2_longd(k+5);
        d25d239x2_longd(k+6);
        d25d239x2_longd(k+7);
    }
    for( ; k <= N4; k ++ )
    {
        d25d239x2_longd(k);
    }
}

void MULTIPLY( char *x, int n )
{
    int j, k;
    unsigned q, r, u;
    long v;
    r = 0;
    for( k = N4; k >= 0; k-- )
    {
        q = n * x[k] + r;
        r = q / 10;
        x[k] = q - r * 10;
    }
}

void SUBTRACT( char *x, char *y, char *z )
{
    int k;
    for( k = N4; k >= 0; k-- )
    {
        if( (x[k] = y[k] - z[k]) < 0 )
        {
            x[k] += 10;
            z[k-1]++;
        }
    }
}

void SUBTRACTx2( char *a, char *b, char *c ) {
    int i, j, k;
    for( k = N4; k >= 0; k -= 1 )
    {
        i = c[k];
        j = a[k];
        a[k] = difference[i][j][QUO];
        a[k-1] += difference[i][j][RES];
        j = b[k];
        b[k] = difference[i][j][QUO];
        b[k-1] += difference[i][j][RES];
    }
}

void SET0( char *x )
{
    memset( x, 0, N4 + 1 );
    x[0] = 0;
}

void SET1( char *x )
{
    memset( x, 0, N4 + 1 );
    x[0] = 1;
}

void calculate( void );
void progress( void );
void epilog( void );

int main( int argc, char *argv[] )
{
    int i;
    N = 10000;

    PRECALC_DIVIDE5();
    PRECALC_DIVIDE25();
    PRECALC_DIVIDE239();
    PRECALC_SUBTRACT();

    setbuf(stdout, NULL);

    calculate();

    epilog();

    return 0;
}

void calculate( void )
{
    int j, k;

    N4 = N + 4;

    SET0( a );
    SET1( b );

    j = 2 * N4 + 1;

    SET1( c );

    LONGDIV( c, j );

    for( ; ; )
    {
        if (j < 3) break;

        j -= 2;

        SUBTRACTx2( a, b, c );

        SET1( c );

        DIVIDE25_DIVIDE239x2_LONGDIV( a, b, c, j);

        progress();
    }

    SET1( c );
    SUBTRACTx2( a, b, c );
    DIVIDE5( a );
    DIVIDE239( b );
    MULTIPLY( a, 4 );
    SUBTRACT( a, a, b );
    MULTIPLY( a, 4 );
    progress();
}

void progress( void )
{
    printf(".");
}

void epilog( void )
{
    int j;

    {
        fprintf( stdout, " \n3.");
        for( j = 1; j <= N; j++ )
        {
            fprintf( stdout, "%d", a[j]);
            if( j % 5  == 0 )
                if( j % 50 == 0 )
                    if( j % 250  == 0 )
                        fprintf( stdout, "    <%d>\n\n   ", j );
                    else
                        fprintf( stdout, "\n   " );
                else
                    fprintf( stdout, " " );
        }
    }
}
